/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.hiof.moraa.server.service;

import com.hiof.moraa.mapping.TblAthlete;
import com.hiof.moraa.mapping.TblSupport;
import com.hiof.moraa.server.dao.AthleteDAO;
import com.hiof.moraa.server.dao.AthleteLiveLocationDAO;
import com.hiof.moraa.server.dao.SupportLiveLocationDAO;
import com.hiof.moraa.server.service.model.*;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

/**
 * @author Bergy
 */
@Transactional(readOnly = true)
public class TeamMemberLocationService {

    private MapService mapService;
    private RouteGeographyService routeGeographyService;
    private AthleteDAO athleteDAO;
    private AthleteLiveLocationDAO athleteLiveLocationDAO;
    private SupportLiveLocationDAO supportLiveLocationDAO;

    public void setAthleteDAO(AthleteDAO athleteDAO) {
        this.athleteDAO = athleteDAO;
    }

    public void setRouteGeographyService(RouteGeographyService routeGeographyService) {
        this.routeGeographyService = routeGeographyService;
    }

    public void setMapService(MapService mapService) {
        this.mapService = mapService;
    }

    public void setAthleteLiveLocationDAO(AthleteLiveLocationDAO athleteLiveLocationDAO) {
        this.athleteLiveLocationDAO = athleteLiveLocationDAO;
    }

    public void setSupportLiveLocationDAO(SupportLiveLocationDAO supportLiveLocationDAO) {
        this.supportLiveLocationDAO = supportLiveLocationDAO;
    }

    public TeamMemberLocationPacket getSupportsLocation(int athleteId) throws Exception {
        TeamMemberLocationPacket packet = new TeamMemberLocationPacket();
        TblAthlete athlete = athleteDAO.getAthleteById(athleteId);
        List<MapPoint> routeMapPoint = getRouteMapPoints(athlete);
        List<TblSupport> supports = athleteDAO.getSupports(athleteId);
        for (TblSupport support : supports) {
            packet.addTeamMemberLocationsElement(getSupportRelativePosition(athlete, support, routeMapPoint));
        }
        return packet;
    }

    private List<MapPoint> getRouteMapPoints(TblAthlete athlete) {
        int routeId = athlete.getTblRoute().getId();
        List<MapPoint> routeMapPoint = mapService.getMapPoints(routeId);
        return routeMapPoint;
    }

    private MemberLocationInfo getSupportRelativePosition(TblAthlete athlete, TblSupport support, List<MapPoint> routeMapPoint) throws Exception {
        int userId = support.getTblUser().getId();
        double supportSpeed = 0;

        GeoPoint athleteGeoPoint, supportGeoPoint;
        LiveLocationFeed athleteLiveLocationFeed = athleteLiveLocationDAO.getLatestLiveLocationFeedOfOneAthlete(athlete.getId());
        LiveLocationFeed supportLiveLocationFeed = supportLiveLocationDAO.getLatestLiveLocationFeedOfOneSupport(support.getId());

        if (athleteLiveLocationFeed != null)
            athleteGeoPoint = athleteLiveLocationFeed.getGoogleGeoPoint();
        else
            athleteGeoPoint = routeMapPoint.get(0).getGeoPoint();

        if (supportLiveLocationFeed != null){
            supportGeoPoint = supportLiveLocationFeed.getGoogleGeoPoint();
            supportSpeed = supportLiveLocationFeed.getSpeed();
        }
        else
            supportGeoPoint = routeMapPoint.get(0).getGeoPoint();

        boolean isBehind = determineRelativePosition(supportGeoPoint, athleteGeoPoint, routeMapPoint);

        double distance = routeGeographyService.distanceBetween2PointsInOneRoute(athleteGeoPoint, supportGeoPoint, routeMapPoint);
        //double distance = geometryService.distanceByMeters(athleteGeoPoint, supportGeoPoint);
        return new MemberLocationInfo(userId, distance, isBehind, supportGeoPoint, supportSpeed);
    }

    /**
     * *
     * Return true if support is behind athlete
     *
     * @param supportGeoPoint
     * @param athleteGeoPoint
     * @param routeMapPoint
     * @return
     */
    private boolean determineRelativePosition(GeoPoint supportGeoPoint, GeoPoint athleteGeoPoint, List<MapPoint> routeMapPoint) {
        boolean result = true;
        RelativePosition relativePosition = routeGeographyService.findRelativePositionInOneRoute(supportGeoPoint, athleteGeoPoint, routeMapPoint);
        if (relativePosition == RelativePosition.BEHIND) {
            result = false;
        } else if (relativePosition == RelativePosition.FORWARD) {
            result = true;
        }
        return result;
    }
}
